// 定位与权限工具方法（跨端尽量降级处理）
import { netConfig } from "@/api/net.config";
// #ifdef H5
import { initWxSdk } from "@/utils/wxJssdk";
// #endif
import { useCityStore } from "@/store/modules/city";

export interface GeoCoords {
  longitude: number;
  latitude: number;
}

export interface LocationRawResult extends GeoCoords {
  address?: any;
}

export interface LocationInitOptions {
  isSetCurrentCity?: boolean;
}

export interface LocationService {
  tryInitLocation(options?: LocationInitOptions): Promise<boolean>;
  handlePageShow(options?: LocationInitOptions): Promise<boolean>;
  isLocating(): boolean;
}

export interface LocationServiceOptions {
  cityStore?: ReturnType<typeof useCityStore>;
}

// 获取定位坐标
export function getLocationCoords(options?: {
  type?: "gcj02" | "wgs84";
  geocode?: boolean;
  timeoutMs?: number;
}): Promise<LocationRawResult> {
  const type = options?.type || "gcj02";
  const geocode: any = options?.geocode ?? true;
  const timeoutMs =
    options?.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : 0;

  return new Promise(async (resolve, reject) => {
    let timer: any;
    if (timeoutMs) {
      timer = setTimeout(() => {
        timer && clearTimeout(timer);
        // 模拟 uni 规范的报错文案，便于统一判断
        reject({ errMsg: "getLocation:timeout" });
      }, timeoutMs);
    }
    if (isApp) {
      uni.getLocation({
        type,
        geocode,
        success: (res: any) => {
          timer && clearTimeout(timer);
          resolve({
            longitude: Number(res.longitude),
            latitude: Number(res.latitude),
            address: res?.address,
          });
        },
        fail: (err) => {
          timer && clearTimeout(timer);
          reject(err);
        },
      });
    } else {
      await initWxSdk({ jsApi: "getLocation" });
      wx.ready(function () {
        wx.getLocation({
          type, // 默认为wgs84的gps坐标，如果要返回直接给openLocation用的火星坐标，可传入'gcj02'
          geocode,
          success: function (res: any) {
            console.log(res);

            resolve({
              longitude: Number(res.longitude),
              latitude: Number(res.latitude),
            });
          },
          fail: function (res: any) {
            reject(res);
          },
        });
      });
    }
  });
}

// 是否为权限拒绝类错误
export function isPermissionDenied(err: any): boolean {
  const msg = String(err?.errMsg || err?.message || "").toLowerCase();
  return /auth|denied|permission|权限|拒绝|未授权/.test(msg);
}

// 是否为定位超时错误
export function isTimeoutError(err: any): boolean {
  const msg = String(err?.errMsg || err?.message || "").toLowerCase();
  return /timeout/.test(msg);
}

// 逆地理解析城市（高德）
export async function reverseGeocodeCity(
  lng: number,
  lat: number
): Promise<string> {
  const amapKey = (netConfig as any)?.amapKey as string | undefined;
  if (!amapKey) return "";
  const location = `${lng},${lat}`;
  const url = `https://restapi.amap.com/v3/geocode/regeo?key=${encodeURIComponent(
    amapKey
  )}&location=${encodeURIComponent(location)}`;
  return new Promise<string>((resolve) => {
    uni.request({
      url,
      success: (res) => {
        const data = (res as unknown as { data?: any }).data;
        const comp = data?.regeocode?.addressComponent || {};
        const rawCity = Array.isArray(comp.city) ? comp.city[0] : comp.city;
        const city = rawCity || comp.province || comp.district || "";
        if ((Array.isArray(city) && city.length === 0) || city === "")
          resolve("");
        resolve(city || "");
      },
      fail: () => resolve(""),
    });
  });
}

// 打开应用权限设置（APP端），H5/MP 下为 no-op
export function openAppPermissionSetting(): void {
  try {
    // 官方能力（若存在）
    const anyUni = uni as any;
    if (typeof anyUni.openAppAuthorizeSetting === "function") {
      anyUni.openAppAuthorizeSetting({});
      return;
    }
  } catch {}

  // 降级处理：仅在 APP-PLUS 环境存在 plus 时可用
  const g: any = globalThis as any;
  const plusObj = g?.plus;
  if (!plusObj) return;

  try {
    if (plusObj.os?.name === "Android") {
      const main = plusObj.android.runtimeMainActivity();
      const Intent = plusObj.android.importClass("android.content.Intent");
      const Settings = plusObj.android.importClass("android.provider.Settings");
      const Uri = plusObj.android.importClass("android.net.Uri");
      try {
        const intentLoc = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        main.startActivity(intentLoc);
        return;
      } catch {}
      const intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
      const uri = Uri.fromParts("package", main.getPackageName(), null);
      intent.setData(uri);
      main.startActivity(intent);
      return;
    } else {
      plusObj.runtime.openURL("app-settings:");
    }
  } catch (e) {
    console.warn("打开系统设置失败", e);
  }
}

// 提供统一定位流程的服务，方便页面直接复用
export function createLocationService(
  options?: LocationServiceOptions
): LocationService {
  const cityStore = options?.cityStore ?? useCityStore();
  let locating = false;
  let retryLocationOnShow = false;

  const commitCoordinate = (longitude: number, latitude: number) => {
    cityStore.setCurrentCoordinate({
      longitude: String(longitude),
      latitude: String(latitude),
    });
  };

  const syncCityByLocation = async (
    longitude: number,
    latitude: number,
    isSetCurrentCity: boolean
  ) => {
    try {
      const city = await reverseGeocodeCity(longitude, latitude);
      if (!city) return;
      if (isSetCurrentCity) cityStore.setCurrentCity(city);
      cityStore.setLocationCity(city);
    } catch (err) {
      console.warn("逆地理解析失败", err);
    }
  };

  const tryInitLocation = async (
    opts?: LocationInitOptions
  ): Promise<boolean> => {
    const isSetCurrentCity = !!opts?.isSetCurrentCity;
    if (locating) return false;
    locating = true;
    try {
      const res = await getLocationCoords({ type: "gcj02", geocode: true });
      const lng = Number(res.longitude);
      const lat = Number(res.latitude);
      commitCoordinate(lng, lat);
      const city = (res as any)?.address?.city || "";
      if (city) {
        if (isSetCurrentCity) cityStore.setCurrentCity(city as string);
        cityStore.setLocationCity(city as string);
      } else {
        await syncCityByLocation(lng, lat, isSetCurrentCity);
      }
      return true;
    } catch (err: any) {
      // #ifdef H5
      uni.showToast({ title: "定位失败,稍后重试", icon: "none" });
      // #endif
      // #ifdef APP-PLUS
      const denied = isPermissionDenied(err);
      if (denied) {
        uni.showModal({
          title: "定位权限未开启",
          // content: "请在系统设置中开启定位权限后重试",
          content: "请在系统设置中开启定位权限后重试",
          confirmText: "去设置",
          success: (result) => {
            if (!result.confirm) return;
            retryLocationOnShow = true;
            openAppPermissionSetting();
          },
        });
      } else {
        uni.showToast({ title: "定位失败", icon: "none" });
      }
      // #endif
      return false;
    } finally {
      locating = false;
    }
  };

  const handlePageShow = async (
    opts?: LocationInitOptions
  ): Promise<boolean> => {
    if (!retryLocationOnShow) return false;
    retryLocationOnShow = false;
    await tryInitLocation(opts);
    return true;
  };

  const isLocating = () => locating;

  return {
    tryInitLocation,
    handlePageShow,
    isLocating,
  };
}
